// testconvDlg.cpp : implementation file
//

#include "stdafx.h"
#include "testconv.h"
#include "testconvDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTestconvDlg dialog

CTestconvDlg::CTestconvDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CTestconvDlg::IDD, pParent)
{
	//{{AFX_DATA_INIT(CTestconvDlg)
		// NOTE: the ClassWizard will add member initialization here
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CTestconvDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTestconvDlg)
		// NOTE: the ClassWizard will add DDX and DDV calls here
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTestconvDlg, CDialog)
	//{{AFX_MSG_MAP(CTestconvDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTestconvDlg message handlers

BOOL CTestconvDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu.LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon
	
	// TODO: Add extra initialization here
	OnOK();
	
	return TRUE;  // return TRUE  unless you set the focus to a control
}

void CTestconvDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTestconvDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CTestconvDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

//----------------------------| (640)
//------------| (320)
// 0 1 6 7,  8  9 14 15, 16 17 22 23
// 2 3 4 5, 10 11 12 13, 18 19 20 21
//----------------------------|
// 20 21 ...
// 22 23
//----------------------------|
// 40 41 ...
// 42 43
//----------------------------|
// ...
//----------------------------|
// 640/64 = 10 *2 = 20;
//----------------------------|

const INT tblPMem[8] = {
	0, 1, 6, 7,
	2, 3, 4, 5 };

void ReadBlock(LPBYTE pDst, LPBYTE pSrc, INT iX, INT iY, INT iW, INT iH, INT iBlkW, INT iBlkH)
{
	INT		i;

	INT		ip0 = ((iX/iBlkW)&(~0x3))<<1;
	INT		ip1 = tblPMem[((iX/iBlkW)&0x3) + ((iY/iBlkH)&0x1)*4];

	INT		ip2 = ((((iW+63)/iBlkW)+1)&(~0x1))*2 *(iY/iBlkH/2);
	
	BOOL	bNonPair = (BOOL)(((iH+iBlkH-1) / iBlkH) & 0x1);
	INT		ip		 = (bNonPair && (iH-iY)<=iBlkH)?(ip2+iX/iBlkW):(ip0+ip1+ip2);

	INT		iLoopH   = (iH-iY)>=iBlkH ? iBlkH : (iH-iY);

//	TRACE("p.%2d,%2d(%3d,%3d) in.%2d=%2d+%2d+%2d\n", iX/iBlkW, iY/iBlkH, iX, iY, ip, ip0, ip1, ip2);

	if(!pDst || !pSrc)
		return;

	LPBYTE	pi = pSrc + (ip)*(iBlkW*iBlkH);
	LPBYTE	pd = pDst + iX + iY*iW;


	for(i=0; i<iLoopH; i++) {
		memcpy(pd, pi, min(iW-iX, iBlkW));
		pd  += iW;
		pi  += iBlkW;
	}
}

void ReadBlockC(LPBYTE pDst, LPBYTE pSrc, INT iX, INT iY, INT iW, INT iH, INT iBlkW, INT iBlkH)
{
	INT		i,j;
	
	INT		ip0 = ((iX/iBlkW)&(~0x3))<<1;
	INT		ip1 = tblPMem[((iX/iBlkW)&0x3) + ((iY/iBlkH)&0x1)*4];
	
	INT		ip2 = ((((iW+31)/iBlkW)+1)&(~0x1))*2 *(iY/iBlkH/2);

	BOOL	bNonPair = (BOOL)(((iH+iBlkH-1) / iBlkH) & 0x1);
	INT		ip		 = (bNonPair && (iH-iY)<=iBlkH)?(ip2+iX/iBlkW):(ip0+ip1+ip2);
	
	INT		iLoopH   = (iH-iY)>=iBlkH ? iBlkH : (iH-iY);
	
	TRACE("p.%2d,%2d(%3d,%3d) in.%2d=%2d+%2d+%2d\n", iX/iBlkW, iY/iBlkH, iX, iY, ip, ip0, ip1, ip2);
	
	if(!pDst || !pSrc)
		return;
	
	LPBYTE	pi  = pSrc + (ip)*(iBlkW*iBlkH)*2;
	LPBYTE	pcb = pDst + iX + iY*iW;
	LPBYTE	pcr = pcb  + (iW*iH);

	INT		iBlkCopyW = min(iBlkW, iW-iX);
	
	for(i=0; i<iLoopH; i++) {
		for(j=0; j<iBlkCopyW; j++) {
			pcb[j] = *pi++;
			pcr[j] = *pi++;
		}
		pcb += iW;
		pcr += iW;
		pi += (iBlkW-iBlkCopyW)*2;
	}
}


void CTestconvDlg::OnOK() 
{
	INT i,j;
#if 0
	INT iw=640;	INT ih=480;
#elif 0
	INT iw=320;	INT ih=240;
#elif 1
	INT iw=176; INT ih=144;
#endif
	INT ibw=64;
	INT ibh=32;

	INT iBufW = ((((iw+63)/ibw)+1)&(~0x1))*ibw;
	INT iBufH = (ih+ibh-1)&(~0x1F);

	INT iwc   = iw>>1;
	INT ihc   = ih>>1;
	INT ibwc  = ibw>>1;
	INT ibhc  = ibh;
	INT iBufWc= ((((iwc+31)/ibwc)+1)&(~0x1))*ibwc;
	INT iBufHc= (ihc+ibhc-1)&(~0x1F);

	TCHAR szPath[MAX_PATH];

#define _EN_WRT 1
#if _EN_WRT
	sprintf(szPath, "D:\\LS\\_bin\\mfc_dec_%dx%d.yuv", iw, ih);
	FILE* fp = fopen(szPath, "rb");
	LONG  lSz = 0;
	LPBYTE pIn=NULL;
	if(fp) {
		fseek(fp, 0, SEEK_END);
		lSz = ftell(fp);

//		lSz = iBufW*iBufH;
//		lSz += iBufWc*iBufHc*2;

		fseek(fp, 0, SEEK_SET);
		pIn = new BYTE[lSz];
		fread(pIn, lSz, 1, fp);
		fclose(fp);
	}
	else
		return;

	LPBYTE pi   = pIn;
	LPBYTE pOut = new BYTE[lSz*4];
	memset(pOut, 0x80, lSz*4);
#endif

	//---- Y
	for(j=0; j<ih; j+=ibh) {
		for(i=0; i<iw; i+=ibw) {
#if _EN_WRT
			ReadBlock(pOut, pi, i, j, iw, ih, ibw, ibh);
#else
			ReadBlock(NULL, NULL, i, j, iw, ih, ibw, ibh);
#endif
		}
		TRACE("\n");		
	}

	LPBYTE poC = pOut+iw*ih;
	LPBYTE piC = pi + iBufW*iBufH;

#if 1
	//---- CbCr
	for(j=0; j<ihc; j+=ibhc) {
		for(i=0; i<iwc; i+=ibwc) {
#if _EN_WRT
			ReadBlockC(poC, piC, i, j, iwc, ihc, ibwc, ibhc);
			//if(i==ibwc)
			//	break;
#else
			ReadBlockC(NULL, NULL, i, j, iwc, ihc, ibwc, ibhc);
#endif
		}
		TRACE("\n");
		//if(j==ibhc)
		//	break;
	}
#else
	memset(poC, 0x80, iwc*ihc*2);
#endif


#if _EN_WRT
	sprintf(szPath, "D:\\LS\\_bin\\mfc_dec_%dx%d_conv.yuv", iw, ih);
	fp = fopen(szPath, "wb");
	if(fp) {
		fwrite(pOut, iw*ih*3/2, 1, fp);
		fclose(fp);
	}
	
	if(pIn)
		delete pIn;
	if(pOut)
		delete pOut;
#endif
	CDialog::OnOK();
}

void CTestconvDlg::OnOK2()
{
	FILE* fp = fopen("D:\\LS\\_bin\\mfc_dec_640x480.yuv", "rb");
	LONG  lSz = 0;
	LPBYTE pIn=NULL;
	if(fp) {
		fseek(fp, 0, SEEK_END);
		lSz = ftell(fp);
		fseek(fp, 0, SEEK_SET);
		pIn = new BYTE[lSz];
		fread(pIn, lSz, 1, fp);
		fclose(fp);
	}
	else
		return;

	LPBYTE pi = pIn;

	INT iw = 640;
	INT ih = 480;
	LPBYTE pOut = new BYTE[lSz*4];
	LPBYTE poy = pOut;
	LPBYTE pou = pOut + iw*ih;
	LPBYTE pov = pou  + iw*ih/4;

	INT i,j,k,m,t=0;

	memset(poy, 0, iw*ih);
	memset(pou, 0x11, iw*ih*2);

	INT _BLKW =	64;
	INT _BLKH =	32;

	for(m=0; m<(ih+_BLKW)/_BLKW; m++) {

		t = 0;

		for(k=0; k<iw/_BLKW; k+=2) {
			
			poy = pOut + 0*iw + _BLKW*(k+0) + _BLKH*iw*t + m*_BLKW*iw;
			
			for(i=0; i<_BLKH; i++) {
				memcpy(poy, pi, _BLKW);
				poy += iw;
				pi  += _BLKW;
			}

			if(k*_BLKW<=iw) {
				poy = pOut + _BLKW*(k+1) + _BLKH*iw*t + m*_BLKW*iw;
				for(i=0; i<_BLKH; i++) {				
					memcpy(poy, pi, _BLKW);
					poy += iw;
					pi += _BLKW;
				}
			}

			if((m+1)*_BLKW<ih) {
				
				poy = pOut + _BLKW*(k+0) + _BLKH*iw*(1-t) + m*_BLKW*iw;
				for(i=0; i<_BLKH; i++) {					
					memcpy(poy, pi, _BLKW);
					poy += iw;
					pi += _BLKW;
				}
				
				if(k*_BLKW<=iw) {
					poy = pOut + _BLKW*(k+1) + _BLKH*iw*(1-t) + m*_BLKW*iw;
					for(i=0; i<_BLKH; i++) {					
						memcpy(poy, pi, _BLKW);
						poy += iw;
						pi += _BLKW;
					}
				}
			}
			else 
				t = 1;

			t = (t+1)&1;
		}
	}


	iw /= 2;
	ih /= 2;
	_BLKW /= 2;
//	_BLKH /= 2;

	LPBYTE po2;
	INT ic=0;
	INT oc=0;

	int b = 0;

	for(m=0; m<ih/_BLKH; m+=2) {
		
		t = 0;

		
		for(k=0; k<iw/_BLKW; k+=2) {

			
			if(m==6)
				m = m;

			if((m+t)*_BLKH<ih) {
				poy = pou + _BLKW*(k+0) + (t + m)*_BLKW*iw;
				po2 = pov + _BLKW*(k+0) + (t + m)*_BLKW*iw;
				TRACE("k.%d t+m.%d\n", k, t+m);
				
				for(i=(t+m)*_BLKH; /*i<ih &&*/ i<(t+m+1)*_BLKH; i++) {
					
					for(j=0; j<_BLKW; j++) {

						if(pi-pIn-0x4b000>=0x4b000/2 || poy-pou>=0x4b000/4)
							pi = pi;
						if(poy-pou>=iw*ih || pi-pIn>=iw*ih*4*3/2) {
							//*poy++ = 0xFF;//*pi++;
							//*po2++ = 0xFF;//*pi++;
							pi+=2;
						}
						else {
							*poy++ = *pi++;
							*po2++ = *pi++;
						}
						
						ic+=2;
					}
					poy += (iw-_BLKW);
					po2 += (iw-_BLKW);
				}
				
				if(k*_BLKW<iw) {
					poy = pou + _BLKW*(k+1) + (t + m)*_BLKW*iw;
					po2 = pov + _BLKW*(k+1) + (t + m)*_BLKW*iw;
					TRACE("k.%d t+m.%d\n", k+1, t+m);
					
					for(i=(t+m)*_BLKH; /*i<ih &&*/ i<(t+m+1)*_BLKH; i++) {
						
						for(j=0; j<_BLKW; j++) {
							
							if(pi-pIn-0x4b000>=0x4b000/2 || poy-pou>=0x4b000/4)
								pi = pi;
							if(poy-pou>=iw*ih || pi-pIn>=iw*ih*4*3/2) {
								//*poy++ = 0xFF;//*pi++;
								//*po2++ = 0xFF;//*pi++;
								pi+=2;
							}
							else {
								*poy++ = *pi++;
								*po2++ = *pi++;
							}
							//pi+=2;
							ic+=2;
						}
						poy += (iw-_BLKW);
						po2 += (iw-_BLKW);
					}
				}
			}

			//t = (t+1)&1;
//			m++;

#if 1	
			if((m+t)*_BLKH<ih) {
				poy = pou + _BLKW*(k+0) + (1-t+m)*_BLKW*iw;
				po2 = pov + _BLKW*(k+0) + (1-t+m)*_BLKW*iw;
				TRACE("k.%d m+1-t.%d\n", k, 1-t+m);


				//for(i=0; i<_BLKH; i++) {
				for(i=(1-t+m)*_BLKH; /*i<ih &&*/ i<(1-t+m+1)*_BLKH; i++) {
					
					for(j=0; j<_BLKW; j++) {
						if(pi-pIn-0x4b000>=0x4b000/2 || poy-pou>=0x4b000/4)
							pi = pi;
						if(poy-pou>=iw*ih || pi-pIn>=iw*ih*4*3/2) {
							//*poy++ = 0xFF;//*pi++;
							//*po2++ = 0xFF;//*pi++;
							pi+=2;
						}
						else {
							*poy++ = *pi++;
							*po2++ = *pi++;
						}
						//pi+=2;
						ic+=2;
					}
					poy += (iw-_BLKW);
					po2 += (iw-_BLKW);
				}

				if(k*_BLKW<iw) {
					poy = pou + _BLKW*(k+1) + (1-t+m)*_BLKW*iw;
					po2 = pov + _BLKW*(k+1) + (1-t+m)*_BLKW*iw;
					TRACE("k.%d m+1-t.%d\n", k+1, 1-t+m);

					//for(i=0; i<_BLKH; i++) {
					for(i=(1-t+m)*_BLKH; /*i<ih &&*/ i<(1-t+m+1)*_BLKH; i++) {
						
						for(j=0; j<_BLKW; j++) {
							
							if(pi-pIn-0x4b000>=0x4b000/2 || poy-pou>=0x4b000/4)
								pi = pi;

							if(poy-pou>=iw*ih || pi-pIn>=iw*ih*4*3/2) {
								//*poy++ = 0xFF;//*pi++;
								//*po2++ = 0xFF;//*pi++;
								pi+=2;
							}
							else {
								*poy++ = *pi++;
								*po2++ = *pi++;
							}							
							
						//	pi+=2;
							ic+=2;
						}
						poy += (iw-_BLKW);
						po2 += (iw-_BLKW);
					}
				}
				else
					t = t;
			}
			else 
				t = 1;

//			if(1-t+m>=6)
//				t = 1;

			TRACE("\n");
			//TRACE("in.%d %d u.%d v.%d\n", pi-pIn, ic, poy-pou, po2-pov);
			
			t = (t+1)&1;
#endif
		}
	}


	fp = fopen("D:\\LS\\_bin\\mfc_dec_640x480_conv.yuv", "wb");
	if(fp) {
		fwrite(pOut, lSz, 1, fp);
		fclose(fp);
	}

	if(pIn)
		delete pIn;
	if(pOut)
		delete pOut;
	
	CDialog::OnOK();
}
